<template>
    <!-- :max-height="topHead" -->
    <div style="margin-top: 20px" v-resize="resize" ref="tableBox">
        <el-table :show-summary="showSummary" v-loading="loading" element-loading-text="加载中..." class="tipleTable"
            :class="single ? 'single' : null" ref="multipleTable" v-model:data="tableData" style="width: 100%"
            :max-height="topHead" border row-key="id" lazy :stripe="stripe" :fit="true" :load="childrenLoad"
            :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" :indent="30"
            @selection-change="handleSelectionChange" @sort-change="sortChange" :span-method="spanMethod"
            @expand-change="expandChange" :cell-class-name="cellClassName">


            <!-- 多选框    -->
            <el-table-column v-if="selection" type="selection">
            </el-table-column>

            <!-- 展开列 -->
            <el-table-column v-if="expand" type="expand">
                <template #default="props">
                    <slot name="expand" :row="props.row"></slot>
                </template>
            </el-table-column>

            <!-- v-if="showSortNum"     -->
            <el-table-column :label="showSortIndex.lable" v-if="showSortIndex.show" width="60">
                <template v-slot="scope">
                    <span>
                        {{
                            scope.$index +
                            1 +
                            listQuery.size * (listQuery.current - 1)
                        }}
                    </span>
                </template>
            </el-table-column>

            <template v-for="(item, index) in column" :key="index">
                <!-- 
                    type:"selection"/多选 expand/展开
                    align: 'left' / 'center' / 'right' 对齐方式
                    fixed: 'left' / 'right' 固定头部
                 -->
                <el-table-column :align="item.align || 'center'" :prop="item.prop" :label="item.label" :width="item.width"
                    :fixed="item.fixed" :class-name="item.class || ''">
                    <!-- render slot -->
                    <template v-if="item.render" v-slot="scope">
                        <slot :scope="scope.row" :name="item.prop"></slot>
                    </template>
                    <!-- html -->
                    <template v-else-if="item.html" v-slot="scope">
                        <div :scope="scope.row" v-html="item.html(scope.row, scope.row[item.prop])"></div>
                    </template>

                    <!-- 开关 -->
                    <template v-else-if="item.switch" v-slot="scope">
                        <el-switch v-model.trim="scope.row[item.prop]" active-color="#13ce66" inactive-color="#ff4949"
                            :active-value="item.value[0]||1" :inactive-value="item.value[1] ||0"
                            @change="switchFun(item, scope.row)"></el-switch>
                    </template>

                    <!-- 图片 -->
                    <template v-else-if="item.img" v-slot="scope">
                        <el-image :src="scope.row[item.prop]" lazy fit="cover" :preview-src-list="[scope.row[item.prop]]"
                            preview-teleported />
                    </template>


                    <!-- 操作 -->
                    <template v-else-if="item.actives" v-slot="scope">
                        <template v-for="(i,indexNum) in item.actives" :key="indexNum">
                            <div @click="i.method(scope.row)" type="text" size="small" class="clickA">
                                {{
                                typeof i.name === "function"
                                ? i.name(scope.row)
                                : i.name
                                }}
                            </div>
                        </template>
                    </template>

                </el-table-column>
            </template>

        </el-table>
        <div v-if="hidden">
            <!-- 全局包裹器中文 -->

                <el-pagination v-model:current-page="listQuery.current" v-model:page-size="listQuery.size"
                    layout="total, sizes, prev, pager, next, jumper" :page-sizes="sizes" :total="total"
                    @size-change="handleSizeChange" @current-change="handleCurrentChange" />

        </div>
    </div>
</template>

<script>
import { reactive, ref, toRefs, computed } from "@vue/reactivity";
import { watch, onActivated, watchEffect, onBeforeUnmount, onMounted } from "vue";
import { ElMessage } from "element-plus";
import { useRouter, useRoute } from "vue-router";
//处理分页中文
import zhCn from "element-plus/lib/locale/lang/zh-cn";

/**
 * @name:
 * @description: 表格二次封装
 * showSortIndex: {
      type: Object,
      // default: { show: false },
      default: () => {
        let _obj = { show: false };
        return _obj;
      },
    },
 例如:  :showSortIndex="{ show: true, lable: '序号' }"
 * headHight 和 refHead: headHight是需要减掉的头部高度优先于refHead相邻头部的ref的高度
 * loadData       fun     一级数据接口函数  二级数据所需id默认会在此获取
 * childrenData   fun     二级数据接口函数  添加此函数默认开启数形结构 并且所有一级数据都会带上childen属性
 * params  obj 初始化的时候需要带的参数
 * column    array   表头数据   ==>
 *   表头参数如下：{
 *     props: string 表头key值
 *     label:string 表头名字
 *     width: number 表头该列的宽度
 *     formatter: fun 自定义格式 Function(row, column, cellValue, index)  row:整条数据实例  column:表头实例  cellValue:该条参数值  index:index
 *     actives: array  操作   {method 事件函数  name 操作名称 }
 *            ==>method：val=>{} val为返回的该行的值
 *            ==>name:string /function  当传入为回调函数时 回调参数返回为该行的值 当返回为false时 该操作按钮默认不显示
 *   }
 * render    boolean  是否需要自定义插槽 父组件插槽：    v-slot:prop值="{scope}" scope为该行值
 * html 函数 直接渲染dom  例如 html:(row)=>`<el-button >取消</el-button>`
 * img boolean渲染成图片
 * eg:
 * <template v-slot:avatar="{scope}">
 <img :src="scope.avatar" class="admin_avater" />
 </template>

 * select    function 开启多选框  传递函数 返回value  绑定函数需要在method中声明  value为选中数组 single为true 多选变成单选
 * hidden    boolean  是否显示分页器 不传则默认显示
 * single    boolean  是否开启单选
 *
 * ==================
 * 方法 通过this.$refs.表格名.方法名  调用  eg:this.$refs.table.update({...searchParams}) //搜索并更新表格 searchParams为搜索参数对象
 * reset重置表格  update更新表格  clearSelect清空单选/多选
 * @return:
 */
/*分页器
 * total         number   总条目数
 * current-page.sync      number   当前页数
 * page-size.sync         number   每页限制条数
 * sizes     array    每页显示条目个数，支持 .sync 修饰符
 * layout        string   组件布局，子组件名用逗号分隔
 * hidden        boolean  是否隐藏
 */
export default {
    name: "xtable",
    components: {

    },
    props: {
        // 单独设置Cass
        cellClassName: {
            type: [Function, String],
            default: null
        },
        // 合并行或列
        spanMethod: {
            type: Function,
            default: null
        },
        selection: {
            default: false
        },
        // 第一次是否请求
        firstQuest: {
            default: true
        },
        // 斑马纹
        stripe: {
            default: true
        },
        // [['xx',xx2],[aa,aa2]]
        activeSame: {
            default: []
        },
        // 展开
        expand: {
            default: false
        },
        dealResult: {
            default: null
        },
        //合计
        showSummary: {
            type: Boolean,
            default: false
        },
        // 底部位置
        bottomSize: {
            type: [Number, String],
            default: () => 60,
        },
        // 获取数据的回调函数
        loadData: {
            type: [Function, Array],
            // required: true
        },
        // 传入静态数据，与上面的loadData，两个只能存在一个
        data: {
            type: Array,
        },
        showSortIndex: {
            type: Object,
            // default: { show: false },
            default: () => {
                let _obj = { show: false };
                return _obj;
            },
        },
        childrenData: {
            type: Function,
        },
        column: {
            type: Array,
        },
        hidden: {
            type: Boolean,
            default: true,
        },
        params: {
            type: Object,
        },
        // 接收选中的数组的函数
        select: {
            type: Function,
        },
        // 是否单选
        single: {
            type: Boolean,
            default: false,
        },
        height: {
            type: Number,
        },
        // 滚条高度
        headHight: {
            type: [Number, String],
            default: () => "",
        },
        refHead: {
            type: String,
            default: () => "",
        },
        // 额外的高度
        additional: {
            type: [Number, String],
            default: () => 0,
        },
    },
    directives: {
        resize: {
            // 指令的定义
            mounted(el, binding) {
                let width, height;
                let get = () => {
                    const style = document.defaultView.getComputedStyle(el);
                    if (width !== style.width || height !== style.height) {
                        binding.value({ width, height });
                    }
                    width = style.width;
                    height = style.height;
                };
                el.__vueReize__ = setInterval(get, 200);
            },
            unmounted(el) {
                clearInterval(el.__vueReize__);
            },
        },
    },
    setup(props, context) {
        const route = useRoute();
        const names = {}
        let { emit } = context
        const router = useRouter();
        const locale = zhCn;
        const state = reactive({
            // 接收操作的按钮名字
            getNames: ({ name, value }) => {
                state.names[name] = value
            },
            baseParams: {},
            expandChange: (val, rows) => {
                emit('expandChange', { ...val, rows })
            },
            loading: false,
            screenWidth: "",
            topHead: "1000",
            total: 0,
            listQuery: {
                current: 1,
                size:
                    props.params && props.params.size ? props.params.size : 20,
            },
            tableData: [],
            sizes: [5, 10, 20, 30, 50],
            searchParams: {}, //搜索参数,
            activeRow: {}, //选择当前行
            parentId: 0,
            cutId: "",
            perCodeObj: {},
            setWidth: '',
            names: {},
            getActiveWidth: 0,
        });
        const setBaseParams = () => {
            for (let key in props.params) {
                let str = props.params[key] + ''
                if (!str.includes('-')) {
                    state.baseParams[key] = props.params[key]
                }
            }
        }
        setBaseParams()



        // 设置结果
        const setData = (data) => {
            state.tableData = data
            if (data?.total) { state.total = data.total }
        }
        const getData = (params, callBack) => {
            if (props.loadData) {
                if (typeof props.loadData == "function") {
                    state.loading = true;
                    props.loadData({ ...state.baseParams, ...params })
                        .then(
                            (res) => {
                                let data = res.data;
                                if (res.code == 200) {
                                    setData(data)
                                }
                            },
                            (err) => {
                                console.log(err);
                            }
                        )
                        .finally(() => {
                            state.loading = false;
                            callBack && callBack()
                        });
                }
                if (Array.isArray(props.loadData)) {
                    setData(props.loadData)
                }
            }
        };

        onMounted(() => {
            state.searchParams = { ...state.listQuery, ...props.params }
            if (props.firstQuest) {
                getData({ ...state.searchParams });
            }
        });


        // 获取头部高度
        const tableBox = ref(null);
        //
        const resize = () => {
            getHeight();
        };
        const getHeight = () => {
            if (props.headHight) {
                state.topHead = parseInt(props.headHight);
            } else {
                //窗口高
                let windowHeight = document.documentElement.clientHeight;
                //元素到窗口顶部距离
                if (tableBox.value) {
                    let table__body =
                        tableBox.value.getBoundingClientRect().top;
                    if (table__body) {
                        let bottomSize = Number(props.bottomSize);
                        state.topHead =
                            windowHeight - table__body - bottomSize;
                    } else {
                        state.topHead = 630;
                    }
                }
            }
        };
        const tabelColomClick = (item, row) => {
            item.click && item.click(row);
        };
        const toStr = (par) => {
            return par.toString();
        };
        //切换
        const switchFun = (item, row) => {
            let data = { id: row.id, [item.prop]: row[item.prop] };
            if (item?.switchFun == undefined) return
            item.switchFun({ ...data })
                .then((res) => {
                    ElMessage.success("操作成功");
                })
                .finally(() => {
                    reset();
                });
        };

        // 修改每页展示条数
        const handleSizeChange = (val) => {
            getData({
                ...state.searchParams,
                current: state.listQuery.current,
                size: val,
            });
        };
        // 页数
        const handleCurrentChange = (val) => {
            getData({
                ...state.searchParams,
                current: val,
                size: state.listQuery.size,
            });
        };
        // 通过this.$refs.表格名  调用的方法==============
        // 重置表格 刷新
        const reset = () => {
            state.searchParams = { ...props.params, ...state.listQuery }

            getData({ ...state.searchParams });
        };
        // 更新表格 reset 重置外部参数
        const update = (params, reset = false, callBack) => {
            let refresh = !!params || reset
            clearSelect();
            if (refresh) {
                state.searchParams = { ...state.listQuery, ...params }
            } else {
                state.searchParams = { ...state.searchParams, ...state.listQuery, ...params }
            }
            getData({ ...state.searchParams }, callBack);
        };
        // 清空选项
        const multipleTable = ref(null);
        const clearSelect = () => {
            multipleTable.value.clearSelection();
        };
        //================================================
        // 二级类目
        const childrenLoad = (row, treeNode, resolve) => {
            props.childrenData({ parentId: row.id, size: 100 }).then((res) => {
                if (res.success) {
                    resolve(res.data.list);
                }
            });
        };

        const sortChange = (val, row) => {
            context.$emit("sortChangechild", val);
        };

        const handleSelectionChange = (arr) => {
            emit("checkbox", arr)
        };
        const resetParams = () => {
            state.baseParams = {}
        }

        watch(
            () => props.data,
            (val, oldValue) => {
                if (val != oldValue) {
                    getData({ ...state.searchParams })
                }
            },
            { deep: true, immediate: true }
        );
        watch(
            () => state.tableData,
            (val, oldValue) => {
                if (val != oldValue) {
                    state.perCodeObj = {}
                }
            },
            { deep: true, immediate: true }
        );
        // keep-alive缓存被激活时更新table数据
        onActivated(() => {
            if (tableBox.value) {
                update()
            }
        })

        return {
            ...toRefs(state),
            ...toRefs(props),
            tabelColomClick,
            childrenLoad,
            handleSelectionChange,
            sortChange,
            handleSizeChange,
            handleCurrentChange,
            update,
            clearSelect,
            switchFun,
            toStr,
            multipleTable,
            tableBox,
            resize,
            locale,
            resetParams
        };
    },
};
</script>

<style lang="scss" scoped>
:deep .table_img>img.el-image__inner {
    width: auto !important;
}

.tipleTable {
    border-radius: 10px;

    :deep .yellow {
        color: yellow !important;
    }

    :deep .red {
        color: red !important;
    }

    :deep .green {
        color: green !important;
    }

    //height: 50vh;
    :deep .el-table__body-wrapper {
        height: 100%;
        overflow: auto;

        //padding-bottom: 48px;
        /*滚动条样式*/
        &::-webkit-scrollbar {
            width: 4px;
            height: 14px;
        }

        //滑块
        &::-webkit-scrollbar-thumb {
            border-radius: 10px;
            -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
            background: #ccc;
        }

        //外层轨道
        &::-webkit-scrollbar-track {
            -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
            border-radius: 0;
            background: #fafafa;
        }
    }
}

.el-pagination {
    text-align: right;
    padding: 10px 10px;
}

.el-table th {
    background-color: #fafafa;
}

.single thead tr .el-checkbox__input {
    display: none;
}

.clickA {
    display: inline-block;
    color: #4159e1;
    padding: 0 8px;
    text-decoration: underline;
    cursor: pointer;
}

.clickA:active {
    color: #1879d4;
}

.total {
    padding: 10px 0;
    text-align: right;
}
</style>
